﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework.Input;

namespace _360Mouse
{
    public partial class Form1 : Form
    {

        #region User32 Related

        [DllImport("User32.dll")]
        static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

        [StructLayout(LayoutKind.Explicit)]
        struct INPUT
        {
            [FieldOffset(0)] public uint type;
            [FieldOffset(4)] public MOUSEINPUT mi;
            [FieldOffset(4)] public KEYBDINPUT ki;
        }

        [StructLayout(LayoutKind.Sequential)] 
        struct MOUSEINPUT
        {
            public int dx;
            public int dy;
            public uint mouseData;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)] 
        struct KEYBDINPUT
        {
            public ushort wVk;
            public ushort wScan;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        enum InputType
        {
            INPUT_MOUSE = 0,
            INPUT_KEYBOARD = 1,
            INPUT_HARDWARE = 2
        }

        enum KeyFlags
        {
            EXTENDEDKEY = 0x0001,
            KEYUP = 0x0002,
            KEYDOWN = 0x0000,
            UNICODE = 0x0004,
            SCANCODE = 0x0008
        }

        enum MouseFlags
        {
            Move = 0x0001,
            LeftDown = 0x0002,
            LeftUp = 0x0004,
            RightDown = 0x0008,
            RightUp = 0x0010,
            Absolute = 0x8000,
            Wheel = 0x0080,
            MiddleDown = 0x0020,
            MiddleUp = 0x0040,
            VirtualDesk = 0x4000,
            XDown = 0x0080,
            XUp = 0x0100,
            HWheel = 0x1000
        }

        enum ScanCodes
        {
            DIK_SPACE = 0x39,
            DIK_TAB = 0x0F,
            DIK_LSHIFT = 0x2A,
            DIK_LCONTROL = 0x1D,
            DIK_LMENU = 0x38,
            DIK_7 = 0x08,
            DIK_8 = 0x09,
            DIK_ESCAPE = 0x01,

            DIK_Q=0x10,
            DIK_W=0x11,
            DIK_E=0x12,
            DIK_R=0x13,
            DIK_T=0x14,
            DIK_Y=0x15,
            DIK_U=0x16,
            DIK_I=0x17,
            DIK_O=0x18,
            DIK_P=0x19,
            DIK_A=0x1E,
            DIK_S=0x1F,
            DIK_D=0x20,
            DIK_F=0x21,
            DIK_G=0x22,
            DIK_H=0x23,
            DIK_J=0x24,
            DIK_K=0x25,
            DIK_L=0x26,
            DIK_Z=0x2C,
            DIK_X=0x2D,
            DIK_C=0x2E,
            DIK_V=0x2F,
            DIK_B=0x30,
            DIK_N=0x31,
            DIK_M=0x32
        }

        #endregion

        #region Initialization

        public Form1()
        {
            InitializeComponent();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = 10;
            timer.Start();
        }

        #endregion

        #region Global Variables

        Timer timer = new Timer();
        int mouseSensitivity = 27;
        float joySensitivitySlow = 0.28f;
        float joySensitivityFast = 0.45f;
        float triggerSensitivity = 0.03f;
        INPUT structInput;

        GamePadState previousState;
        bool rightTrigger = false;
        bool leftTrigger = false;
        bool navRight = false;
        bool navLeft = false;
        bool navUp = false;
        bool navDown = false;
        bool slowEnabled = false;

        #endregion

        void timer_Tick(object sender, EventArgs e)
        {
            GamePadState newState = Microsoft.Xna.Framework.Input.GamePad.GetState(Microsoft.Xna.Framework.PlayerIndex.One);

            #region Joystick Cursor

            if (Math.Abs(newState.ThumbSticks.Right.X + newState.ThumbSticks.Right.Y) > 0.1)
            {
                structInput.mi.dwFlags = (uint)MouseFlags.Move;
                structInput.mi.dx = (int)(newState.ThumbSticks.Right.X * mouseSensitivity);
                structInput.mi.dy = (int)(newState.ThumbSticks.Right.Y * -mouseSensitivity);
                SendInput();
            }

            #endregion

            #region Joystick Movement

            if ((newState.ThumbSticks.Left.X > joySensitivitySlow) != navRight)
            {
                navRight = newState.ThumbSticks.Left.X > joySensitivitySlow;
                keyPress(ScanCodes.DIK_D, !navRight);
            }
            else if ((newState.ThumbSticks.Left.X < -joySensitivitySlow) != navLeft)
            {
                navLeft = newState.ThumbSticks.Left.X < -joySensitivitySlow;
                keyPress(ScanCodes.DIK_A, !navLeft);
            }
            if ((newState.ThumbSticks.Left.Y > joySensitivitySlow) != navUp)
            {
                navUp = newState.ThumbSticks.Left.Y > joySensitivitySlow;
                keyPress(ScanCodes.DIK_W, !navUp);
            }
            else if ((newState.ThumbSticks.Left.Y < -joySensitivitySlow) != navDown)
            {
                navDown = newState.ThumbSticks.Left.Y < -joySensitivitySlow;
                keyPress(ScanCodes.DIK_S, !navDown);
            }

            #endregion

            #region Stick Presses

            if (newState.Buttons.LeftStick != previousState.Buttons.LeftStick)
            {
                keyPress(ScanCodes.DIK_Y, newState.Buttons.LeftStick == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.Buttons.RightStick != previousState.Buttons.RightStick)
            {
                keyPress(ScanCodes.DIK_X, newState.Buttons.RightStick == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            #endregion

            #region Triggers

            if ((newState.Triggers.Right > triggerSensitivity) != rightTrigger)
            {
                rightTrigger = (newState.Triggers.Right > triggerSensitivity);
                keyPress(ScanCodes.DIK_R, !rightTrigger);
            }

            if ((newState.Triggers.Left > triggerSensitivity) != leftTrigger)
            {
                leftTrigger = (newState.Triggers.Left > triggerSensitivity);
                keyPress(ScanCodes.DIK_T, !leftTrigger);
            }

            #endregion

            #region Shoulders

            if (newState.Buttons.LeftShoulder != previousState.Buttons.LeftShoulder)
            {
                keyPress(ScanCodes.DIK_C, newState.Buttons.LeftShoulder == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.Buttons.RightShoulder != previousState.Buttons.RightShoulder)
            {
                keyPress(ScanCodes.DIK_V, newState.Buttons.RightShoulder == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            #endregion

            #region Buttons Standard

            if (newState.Buttons.A != previousState.Buttons.A)
            {
                keyPress(ScanCodes.DIK_B, newState.Buttons.A == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.Buttons.B != previousState.Buttons.B)
            {
                keyPress(ScanCodes.DIK_N, newState.Buttons.B == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.Buttons.Y != previousState.Buttons.Y)
            {
                keyPress(ScanCodes.DIK_M, newState.Buttons.Y == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.Buttons.X != previousState.Buttons.X)
            {
                keyPress(ScanCodes.DIK_F, newState.Buttons.X == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            #endregion

            #region Buttons Top

            if (newState.Buttons.Start != previousState.Buttons.Start)
            {
                keyPress(ScanCodes.DIK_G, newState.Buttons.Start == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.Buttons.Back != previousState.Buttons.Back)
            {
                keyPress(ScanCodes.DIK_H, newState.Buttons.Back == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.Buttons.BigButton != previousState.Buttons.BigButton)
            {
                keyPress(ScanCodes.DIK_E, newState.Buttons.BigButton == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            #endregion

            #region DPad

            if (newState.DPad.Right != previousState.DPad.Right)
            {
                keyPress(ScanCodes.DIK_J, newState.DPad.Right == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.DPad.Left != previousState.DPad.Left)
            {
                keyPress(ScanCodes.DIK_K, newState.DPad.Left == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.DPad.Up != previousState.DPad.Up)
            {
                keyPress(ScanCodes.DIK_L, newState.DPad.Up == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            if (newState.DPad.Down != previousState.DPad.Down)
            {
                keyPress(ScanCodes.DIK_Q, newState.DPad.Down == Microsoft.Xna.Framework.Input.ButtonState.Released);
            }

            #endregion

            previousState = newState;
        }

        void mousePress(MouseFlags flag)
        {
            structInput.mi.dwFlags = (uint)flag;
            SendInput();
        }

        void keyPress(ScanCodes key, bool keyUp)
        {
            structInput.type = (int)InputType.INPUT_KEYBOARD;
            structInput.ki.dwFlags = (uint)KeyFlags.SCANCODE;
            if (keyUp) structInput.ki.dwFlags += (uint)KeyFlags.KEYUP;
            structInput.ki.wScan = (ushort)key;
            SendInput();
        }

        void SendInput()
        {
            SendInput(1, ref structInput, Marshal.SizeOf(structInput));
            structInput = new INPUT();
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            mouseSensitivity = trackBar1.Value;
        }

    }
}
